home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C++ / Applications / ResAnomaly 1.2 / ResAnomaly Source / LtDynamicArray.cp < prev    next >
Encoding:
Text File  |  1995-06-09  |  11.9 KB  |  422 lines  |  [TEXT/MPCC]

  1. #include "LtDynamicArray.h"
  2.  
  3. #include <UMemoryMgr.h>
  4.  
  5. #define arrayIndex_Last 0x7FFFFFFF
  6. #define arrayIndex_Bad 0
  7.  
  8. // ---------------------------------------------------------------------------
  9. //        • LtDynamicArray
  10. // ---------------------------------------------------------------------------
  11. //    /*const*/ruct an empty Array of items of the specified size
  12. //
  13. //    Errors:
  14. //        /*const*/ruction can fail if there is not enough memory to create
  15. //        the Handle for storing the items
  16.  
  17. template<class T>
  18. LtDynamicArray<T>::LtDynamicArray()
  19. {
  20.     mItemSize = sizeof(T);
  21.     mItemCount = 0;
  22.     mItemsH = (T**)NewHandle(0);
  23.     ThrowIfMemFail_(mItemsH);
  24. }
  25.  
  26.  
  27. // ---------------------------------------------------------------------------
  28. //        • LtDynamicArray
  29. // ---------------------------------------------------------------------------
  30. //    /*const*/ruct an Array of items using an existing Handle.
  31. //
  32. //    Caller is responsible for ensuring that inItemsHandle is a valid
  33. //    Handle of Pointer values
  34. //
  35. //    The Array assumes ownership of inItemsHandle, meaning that the Array
  36. //    is responsible for disposing of it.
  37.  
  38. template<class T>
  39. LtDynamicArray<T>::LtDynamicArray(T **inItemsHandle)
  40. {
  41.     mItemSize = sizeof(T);
  42.     mItemsH = inItemsHandle;
  43.     mItemCount = GetHandleSize((Handle)inItemsHandle) / mItemSize;
  44. }
  45.  
  46.  
  47. // ---------------------------------------------------------------------------
  48. //        • ~LtDynamicArray
  49. // ---------------------------------------------------------------------------
  50. //    Destructor
  51.  
  52. template<class T>
  53. LtDynamicArray<T>::~LtDynamicArray()
  54. {
  55.     if (mItemsH != nil) {
  56.         DisposeHandle((Handle)mItemsH);
  57.     }
  58. }
  59.  
  60.  
  61. // ---------------------------------------------------------------------------
  62. //        • GetCount
  63. // ---------------------------------------------------------------------------
  64. //    Return the number of items in an Array
  65.  
  66. template<class T> Int32
  67. LtDynamicArray<T>::GetCount() const
  68. {
  69.     return mItemCount;
  70. }
  71.  
  72.  
  73. // ---------------------------------------------------------------------------
  74. //        • InsertItemsAt
  75. // ---------------------------------------------------------------------------
  76. //    Insert items at the specified position in an Array
  77. //
  78. //    inCount items are inserted into the Array starting at inAtIndex.
  79. //    All items are set to the same value, as specified by inItem.
  80. //
  81. //    If inAtIndex is greater than the number of items in the Array,
  82. //    then the items are inserted after the last item.
  83. //
  84. //    Errors:
  85. //        Insertion can fail if there is not enough memory to store
  86. //        the new items 
  87.  
  88. template <class T> void
  89. LtDynamicArray<T>::InsertItemsAt(
  90.     Uint32    inCount,
  91.     Int32    inAtIndex,
  92.     T    *inItem)
  93. {
  94.     if (inCount < 1) {                // Exit if nothing to insert
  95.         return;
  96.     }
  97.                                     // Grow storage
  98.     Int32    newCount = mItemCount + inCount;
  99.     SetHandleSize((Handle) mItemsH, newCount * mItemSize);
  100.     ThrowIfMemError_();
  101.     
  102.     Int32    saveCount = mItemCount;
  103.     mItemCount = newCount;
  104.     
  105.     if (inAtIndex > saveCount) {    // Check upper bound
  106.         inAtIndex = saveCount + 1;    // Insert at end of Array
  107.         
  108.     } else {                        // Insert at start or middle of Array
  109.         if (inAtIndex < 1) {        // Check lower bound
  110.             inAtIndex = 1;            // Insert at start of Array
  111.         }
  112.         
  113.         if (saveCount > 0) {         // Move existing items to make
  114.                                     //   room for new ones
  115.             ShiftItems(inAtIndex, saveCount, inAtIndex + inCount);
  116.         }
  117.     }
  118.                                     // Inserted items are all set
  119.                                     //   to the same value, if specified
  120.     if (inItem != nil) {
  121.         Int32    index = inAtIndex;
  122.         do {
  123.             PokeItem(index, inItem);
  124.         } while (++index < inAtIndex + inCount);
  125.     }
  126.     
  127. }
  128.  
  129.  
  130. // ---------------------------------------------------------------------------
  131. //        • RemoveItemsAt
  132. // ---------------------------------------------------------------------------
  133. //    Remove items from an Array starting at a specified position
  134. //
  135. //    Does nothing if inAtIndex is out of range. Checks if inCount would remove
  136. //    items past the end of the Array, and adjusts it accordingly to remove
  137. //    the items from inAtIndex to the end of the Array. That means you can pass
  138. //    a large number (0x7FFFFFFF, the maximum, positive, 32-bit integer) to
  139. //    remove the items from inAtIndex to the end of the Array.
  140.  
  141. template<class T> void
  142. LtDynamicArray<T>::RemoveItemsAt(
  143.     Uint32    inCount,
  144.     Int32    inAtIndex)
  145. {
  146.                                     // Check for special last item flag
  147.     if (inAtIndex == arrayIndex_Last) {
  148.         inAtIndex = mItemCount;
  149.     }
  150.                                         // Make sure inAtIndex is in range
  151.     if (inAtIndex > 0  &&  inAtIndex <= mItemCount) {
  152.     
  153.         if (inAtIndex + inCount <= mItemCount) {
  154.                                     // Removing items from the middle
  155.                                     // Shift down items that are above
  156.                                     //   the ones being removed
  157.             ShiftItems(inAtIndex + inCount, mItemCount, inAtIndex);
  158.             
  159.         } else {                    // Removing items at the end
  160.                                     // Limit inCount to the number of items
  161.                                     //   from inWhere to the end
  162.             inCount = mItemCount - inAtIndex + 1;
  163.         }
  164.         
  165.         mItemCount -= inCount;        // Reduce storage
  166.         SetHandleSize((Handle) mItemsH, mItemCount * mItemSize);
  167.     }
  168. }
  169.  
  170.  
  171. // ---------------------------------------------------------------------------
  172. //        • FetchItemAt
  173. // ---------------------------------------------------------------------------
  174. //    Pass back the Item at the specified index
  175. //
  176. //    Returns true if an item exists at inIndex (and sets outItem)
  177. //    Returns false if inIndex is out of range (and leave outItem unchanged)
  178.  
  179. template<class T> Boolean
  180. LtDynamicArray<T>::FetchItemAt(
  181.     Int32    inAtIndex,
  182.     T    *outItem)                // Pointer to the item
  183. {
  184.     Boolean    itemExists = false;
  185.     
  186.     if (inAtIndex == arrayIndex_Last) {
  187.         inAtIndex = mItemCount;
  188.     }
  189.                                     // Check that index is in range
  190.     if (inAtIndex > 0  &&  inAtIndex <= mItemCount) {
  191.         PeekItem(inAtIndex, outItem);
  192.         itemExists = true;
  193.     }
  194.     return itemExists;
  195. }
  196.  
  197.  
  198. // ---------------------------------------------------------------------------
  199. //        • SetItemAt
  200. // ---------------------------------------------------------------------------
  201. //    Sets the value of the Item at the specified index
  202. //
  203. //    inItem is a pointer to the item data. The Array makes and stores
  204. //    a copy of the item data.
  205. //
  206. //    Does nothing if inIndex is out of range
  207.  
  208. template<class T> void
  209. LtDynamicArray<T>::SetItemAt(
  210.     Int32    inAtIndex,
  211.     const T    *inItem)                // Pointer to the item
  212. {
  213.     if (inAtIndex == arrayIndex_Last) {
  214.         inAtIndex = mItemCount;
  215.     }
  216.  
  217.                                     // Check that index is in range
  218.     if (inAtIndex > 0  &&  inAtIndex <= mItemCount) {
  219.         PokeItem(inAtIndex, inItem);
  220.     }
  221. }
  222.  
  223.  
  224. // ---------------------------------------------------------------------------
  225. //        • SwapItems
  226. // ---------------------------------------------------------------------------
  227. //    Swap the values of the Items at the specified indices
  228. //
  229. //    Does nothing if either index is out of range
  230.  
  231. template<class T> void
  232. LtDynamicArray<T>::SwapItems(
  233.     Int32    inIndexA,
  234.     Int32    inIndexB)
  235. {
  236.     if (inIndexA == arrayIndex_Last) {
  237.         inIndexA = mItemCount;
  238.     }
  239.     if (inIndexB == arrayIndex_Last) {
  240.         inIndexB = mItemCount;
  241.     }
  242.                                     // Do nothing if either index is out
  243.                                     //   of range
  244.     if ( (inIndexA > 0 && inIndexA <= mItemCount)  &&
  245.          (inIndexB > 0 && inIndexB <= mItemCount) ) {
  246.          
  247.                                      // Store copy of item A
  248.         StPointerBlock    itemACopy(mItemSize);
  249.         PeekItem(inIndexA, (T*)itemACopy.mPtr);
  250.         
  251.         PokeItem(inIndexA, (T*)GetItemPtr(inIndexB));    // A = B
  252.         PokeItem(inIndexB, (T*)itemACopy.mPtr);            // B = Copy of A
  253.     }
  254. }
  255.  
  256.  
  257. // ---------------------------------------------------------------------------
  258. //        • MoveItem
  259. // ---------------------------------------------------------------------------
  260. //    Move an item from one position to another in an Array. The net result
  261. //    is the same as removing the item and inserting at a new position.
  262. //
  263. //    Does nothing if either index is out of range
  264. //
  265. //    Example:
  266. //                BEFORE                        AFTER MoveItem(2, 6)
  267. //        index    1  2  3  4  5  6            1  2  3  4  5  6
  268. //        item    a  b  c  d  e  f            a  c  d  e  b  f
  269.  
  270. template<class T> void
  271. LtDynamicArray<T>::MoveItem(
  272.     Int32    inFromIndex,
  273.     Int32    inToIndex)
  274. {
  275.     if (inFromIndex == arrayIndex_Last) {
  276.         inFromIndex = mItemCount;
  277.     }
  278.     if (inToIndex == arrayIndex_Last) {
  279.         inToIndex = mItemCount;
  280.     }
  281.                                     // Do nothing if either index is out
  282.                                     //   of range or if "from" and "to"
  283.                                     //   indices are the same
  284.     if ( (inFromIndex > 0 && inFromIndex <= mItemCount)  &&
  285.          (inToIndex > 0   && inToIndex <= mItemCount)  &&
  286.          (inFromIndex != inToIndex) ) {
  287.         
  288.                                     // Store copy of item to move
  289.         StPointerBlock    itemToMove(mItemSize);
  290.         PeekItem(inFromIndex, (T*)itemToMove.mPtr);
  291.         
  292.         if (inFromIndex < inToIndex) {
  293.                                     // Move item to a higher index
  294.                                     // Shift items between "from" and "to"
  295.                                     //   down one spot
  296.             ShiftItems(inFromIndex + 1, inToIndex, inFromIndex);
  297.         } else {
  298.                                     // Move item to a lower index
  299.                                     // Shift items between "to" and "from"
  300.                                     //   up one spot
  301.             ShiftItems(inToIndex, inFromIndex - 1, inToIndex + 1);
  302.         }
  303.         
  304.                                     // Store item at new position
  305.         PokeItem(inToIndex, (T*)itemToMove.mPtr);
  306.     }
  307. }
  308.  
  309.  
  310. // ---------------------------------------------------------------------------
  311. //        • FetchIndexOf
  312. // ---------------------------------------------------------------------------
  313. //    Returns the index of the specified item within the Array
  314. //
  315. //    Returns arrayIndex_Bad if the item is not in the Array
  316.  
  317. template <class T> Int32
  318. LtDynamicArray<T>::FetchIndexOf(
  319.     const T    *inItem) const        // Pointer to the item to find
  320. {
  321.     Int32    findIndex = 0;            // Search from beginning of Array
  322.     
  323.     while (++findIndex <= mItemCount) {
  324.         if (BlocksAreEqual(inItem, GetItemPtr(findIndex), mItemSize)) {
  325.             break;
  326.         }
  327.     }
  328.     
  329.     if (findIndex > mItemCount) {    // Search stopped because we reached the 
  330.         findIndex = arrayIndex_Bad;    //   end without finding the item
  331.     }
  332.  
  333.     return findIndex;
  334. }
  335.  
  336.  
  337. // ---------------------------------------------------------------------------
  338. //        • Remove
  339. // ---------------------------------------------------------------------------
  340. //    Remove an item from an Array
  341. template<class T> void
  342. LtDynamicArray<T>::Remove(
  343.     const T    *inItem)                // Pointer to the item to remove
  344. {
  345.     Int32    index = FetchIndexOf(inItem);
  346.     if (index != arrayIndex_Bad) {
  347.         RemoveItemsAt(1, index);
  348.     }
  349. }
  350.  
  351.  
  352. // ---------------------------------------------------------------------------
  353. //        • GetItemPtr
  354. // ---------------------------------------------------------------------------
  355. //    Returns a pointer to the start of an Items data within the internal
  356. //    storage Handle.
  357. //
  358. //    WARNING: The return pointer references information inside a
  359. //    relocatable block. This pointer will become invalid if the
  360. //    Handle block moves.
  361.  
  362. template <class T> T*
  363. LtDynamicArray<T>::GetItemPtr(
  364.     Int32    inAtIndex) const
  365. {
  366.     return &(*mItemsH)[inAtIndex - 1];/* + (inAtIndex - 1) * mItemSize);*/
  367. }
  368.  
  369.  
  370. // ---------------------------------------------------------------------------
  371. //        • PeekItem
  372. // ---------------------------------------------------------------------------
  373. //    Retrieves the Item at the specified index
  374. //
  375. //    For internal use. Performs no bounds checking.
  376.  
  377. template<class T>void
  378. LtDynamicArray<T>::PeekItem(
  379.     Int32    inAtIndex,
  380.     T    *outItem) const
  381. {
  382.     ::BlockMoveData(GetItemPtr(inAtIndex), outItem, mItemSize);
  383. }
  384.  
  385.  
  386. // ---------------------------------------------------------------------------
  387. //        • PokeItem
  388. // ---------------------------------------------------------------------------
  389. //    Stores the Item at a specified index
  390. //
  391. //    For internal use. Performs no bounds checking.
  392.  
  393. template <class T> void
  394. LtDynamicArray<T>::PokeItem(
  395.     Int32    inAtIndex,
  396.     const T    *inItem)
  397. {
  398.     ::BlockMoveData(inItem, GetItemPtr(inAtIndex), mItemSize);
  399. }
  400.  
  401.  
  402. // ---------------------------------------------------------------------------
  403. //        • ShiftItems
  404. // ---------------------------------------------------------------------------
  405. //    Moves items within the Handle used for internal storage
  406. //        Moves items in the range inStartPos to inEndPos (inclusive) so
  407. //        that those items start at index inDestPos, overwriting any items
  408. //        that were there.
  409. //
  410. //    For internal use. Performs no bounds checking.
  411.  
  412. template <class T> void
  413. LtDynamicArray<T>::ShiftItems(
  414.     Int32    inStartPos,
  415.     Int32    inEndPos,
  416.     Int32    inDestPos)
  417. {
  418.     ::BlockMoveData(*mItemsH + (inStartPos - 1) /** mItemSize*/,
  419.                     *mItemsH + (inDestPos - 1) /** mItemSize*/,
  420.                     (inEndPos - inStartPos + 1) * mItemSize);
  421. }
  422.